package fourmiefight.metier;

import org.dyn4j.geometry.Circle;
import org.dyn4j.geometry.Vector2;

import fourmiefight.abstractionlib2d.CustomBody;
import fourmiefight.ihm.FourmiView;
import fourmiefight.tools.Signals;

public class Fourmi extends CustomBody
{
	private static final int NB_TICS_BEFORE_PH = 10;
	// Etats possibles
	public enum State 
	{ 
		RECHERCHE, 
		RAMENE_NOURRITURE, 
		SUIT_PHEROMONES,
	};
	
	private static final double WIDTH = 0.02;
	
	// Attributs
	protected int nourritureTransportee;
	private Fourmiliere fourmiliere;
	
	private int currentTic = -1;
	private int maxTic = -1;
	private int currentTicNb = 0;
	private Vector2 wayToGoBackHome = null;
	
	// Booleen permettant à la fourmi de calculer une nouvelle trajectoire
    protected boolean haveToCalculate = false;
    
    private boolean killMe = false;

    private State currentState;
	
	// - Constructeurs
	
	public Fourmi(Fourmiliere fourm) 
	{
		this.fourmiliere = fourm;
		view = new FourmiView();
		currentState = State.RECHERCHE;
		Circle circle = new Circle(WIDTH);
        this.addFixture(circle);
        this.setMass();
	}
	
	// - Getteurs & Setteurs
	public int getIdFourmi() 
	{
		return fourmiliere.getIdd();
	}
	
	public int getNourritureTransportee() 
	{
		return nourritureTransportee;
	}
	public void setNourritureTransportee(int nourritureTransportee) 
	{
		this.nourritureTransportee = nourritureTransportee;
	}
	
	public String toString() 
	{
		return "Fourmi num " + this.getIdFourmi();
	}

	public void notifyATic()
	{
		if(!killMe)
		{
			updateState(Signals.AUCUNE_COLLISION);
		}
	}
    
    private void calculateNextVector()
    {
    	switch (currentState) 
    	{
		case RECHERCHE:
			if(haveToCalculate)
	    	{
		    	int sign1 = 1;
		        int sign2 = 1;
		        if(Math.random() <= 0.5)
		        {
		        	sign1 = -1;
		        }
		        
		        if(Math.random() <= 0.5)
		        {
		        	sign2 = -1;
		        }
		    	Vector2 v = new Vector2(sign1 * Math.random(), sign2 * Math.random());
	    		updateView(v);
		        haveToCalculate = false;
		        maxTic = -1;
	    	}
			
			// if (CONTACT avec Phéromone)
			// this.setActionSuivant("SUIVRE_PHEROMONE");	
			// elseif (CONTACT avec Fourmiliere)
			// this.setActionSuivant("RAMENERE_NOURITURE");	
			//if (CONTACT_NOURRITURE) this.currentState=RECOLTE;
			
			break;
		case SUIT_PHEROMONES:
			System.out.println("Suivre une phéromone");
			// if (CONTACT avec Phéromone)
			// this.setActionSuivant("SUIVRE_PHEROMONE");	
			// elseif (CONTACT avec Fourmiliere)
			// this.setActionSuivant("RAMENERE_NOURITURE");	
			break;
		case RAMENE_NOURRITURE:
			System.out.println("Ramener nourriture");
			
			if(wayToGoBackHome != null)
			{
				this.setVelocity(wayToGoBackHome);
				wayToGoBackHome = null;
			}
			
			// if (CONTACT avec Phéromone)
			// this.setActionSuivant("SUIVRE_PHEROMONE");	
			// elseif (CONTACT avec Fourmiliere)
			// this.setActionSuivant("RAMENERE_NOURITURE");	
			break;

		default:
			break;
		}
    }
    
    public boolean updateState(Signals signal, int... idFourmilliere)
    {
    	switch (currentState) 
    	{
		case RECHERCHE:
			switch (signal)
			{
			case COLLISION_FOOD:
				setWayToGoBackHome(new Vector2(getAngle(this.getWorldCenter(), fourmiliere.getWorldCenter())));
				this.setCurrentState(Fourmi.State.RAMENE_NOURRITURE);
				return true;
			case COLLISION_PHEROMONES:
				if(idFourmilliere[0] == this.fourmiliere.getIdd())
				{
					return true;
				}
				break;
			case AUCUNE_COLLISION : 
				currentTic++;
				if(maxTic <= 0)
				{
					double val = Math.random() * 100;
					maxTic = (int) val;
				}
				
				if(maxTic < currentTic)
				{
					haveToCalculate = true;
					maxTic = -1;
					currentTic = -1;
				}
				calculateNextVector();
				break;
			default:
				break;
			}
			break;
		case SUIT_PHEROMONES:
			switch (signal)
			{
			case COLLISION_FOOD:
				setWayToGoBackHome(new Vector2(getAngle(this.getWorldCenter(), fourmiliere.getWorldCenter())));
				this.setCurrentState(Fourmi.State.RAMENE_NOURRITURE);
				break;
			case COLLISION_PHEROMONES:
				if(idFourmilliere[0] == this.fourmiliere.getIdd())
				{
					return true;
				}
				break;
			case AUCUNE_COLLISION:
				if(currentTicNb % NB_TICS_BEFORE_PH * 2 == 0) 
				{
					this.setCurrentState(Fourmi.State.RECHERCHE);
					currentTicNb = 0;
				}
				break;
			default:
				break;
			}
			break;
		case RAMENE_NOURRITURE:
			switch (signal)
			{
			case COLLISION_FOURMILLIERE:
				if(idFourmilliere[0] == fourmiliere.getIdd())
				{
					this.deposerNourriture();
					this.setVelocity(new Vector2(this.getVelocity().getDirection()));
					currentState = State.RECHERCHE;
					return true;
				}
				break;
			case AUCUNE_COLLISION:
				if(currentTicNb % NB_TICS_BEFORE_PH == 0) 
				{
					Pheromone phephe = new Pheromone(this.getWorldCenter().x, this.getWorldCenter().y);
					phephe.setDirectionToTheFood(new Vector2(-this.getVelocity().x, -this.getVelocity().y).getDirection());
					this.getWorld().addBody(phephe);
					fourmiliere.ajouterPheromone(phephe);
					currentTicNb = 0;
				}
				currentTicNb++;
				if(wayToGoBackHome != null)
				{
					this.setVelocity(wayToGoBackHome);
					wayToGoBackHome = null;
				}
				break;
			default:
				break;
			}
			break;
		default:
			break;
		}
    	
    	return false;
    }
    
    private void deposerNourriture() 
    {
    	this.fourmiliere.addFood(this.nourritureTransportee);
    	this.nourritureTransportee = 0;
	}

	public static double getAngle(Vector2 position1, Vector2 position2)
    {
        return Math.atan2(position2.y - position1.y, position2.x - position1.x);
    }
    
    public void setWayToGoBackHome(Vector2 vector)
    {
    	wayToGoBackHome = vector;
    }
    
	public void seServirEnNourriture(Food food2) 
	{
		int f = food2.decreaseFoodCount();
		this.setNourritureTransportee(f);
	}

	public void suivrePheromone(Pheromone ph)
	{
		this.setVelocity(new Vector2(ph.getDirectionToTheFood()));
	}
    
	private void updateView(Vector2 v) 
	{
		this.setVelocity(v);
	}
	
	public State getCurrentState()
	{
		return currentState;
	}
	
	public void setCurrentState(State state)
	{
		currentState = state;
	}

	public boolean isKillMe() 
	{
		return killMe;
	}

	public void setKillMe(boolean killMe) 
	{
		this.killMe = killMe;
	}
}
